﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CrmContacto.Contracts.Services;
using CrmContacto.Contracts;
using CrmContacto.Data;
using System.Transactions;
using CrmContacto.Contracts.Enums;
using System.Text.RegularExpressions;
using CrmContacto.Services.Common;
using Web.Framework.Svc;
using System.Net.Mail;
using System.Threading;
using System.IO;
using CrmContacto.Contracts.Contracts;
using Web.Framework.Translate;
using CrmContacto.Contracts.Contracts.Search;
using CrmContacto.Services.Classes;
using System.Configuration;
using System.Globalization;
using System.Linq.Expressions;
using System.Data.Objects;
using CrmContacto.Services.Marketing;

namespace CrmContacto.Services
{
    public class PuntoDeVentaService : IPuntoDeVentaService
    {
        public Dictionary<string, string> GetCompanyConfigurationKeyValues(int companyId)
        {
            return ListsCrm.GetCompanyConfigurationKeyValues(companyId);
        }

        public List<CompanyConfiguration> GetCompanyConfigurations()
        {
            return ListsCrm.GetCompanyConfigurations();            
        }

        public List<MaestroBase> GetCampaniasActivas(CampaniasActivasSearch search)
        {
            return ListsCrm.GetCampaniasActivas(search);
        }       

        public List<MaestroBase> GetTipoDocumento(int paisId)
        {
            return ListsCrm.GetTipoDocumento(paisId);
        }
       
        public List<Pais> GetPaisesDto(ServiceOptions options, PaisSearch search)
        {
            CrmContactoAdminService service = new CrmContactoAdminService();
            return service.GetPaisesDto(options, search);
        }

        public List<MaestroBase> GetProvincias(int paisId)
        {
            return ListsCrm.GetProvincias(paisId);
        }

        public List<MaestroBase> GetCategoriasDeContacto(MaestroBaseSearch searchMaestroBase)
        {
            return ListsCrm.GetCategoriasDeContacto(searchMaestroBase);
        }

        public void ActivarEntidad(ServiceOptions options, string entidad, int estado, int entidadId)
        {
            CrmContacto.Services.CrmContactoAdminService svr = new CrmContactoAdminService();
            svr.ActivarEntidad(options, entidad, estado, entidadId);
        }

        public CustomerSearchResult SearchForCustomerByNameOrDocOrEmail(CustomerSearchParam searchParam)
        {
            CustomerSearchResult result = new CustomerSearchResult();
            List<PtoVentaRegistroCliente> registroList = new List<PtoVentaRegistroCliente>();
            PtoVentaRegistroCliente registro = new PtoVentaRegistroCliente();
            string nameOrdocOrEmail = searchParam.Nombre;
            nameOrdocOrEmail = nameOrdocOrEmail.ToLower();
            using (CrmContactoEntities ctxCrm = new CrmContactoEntities())
            {
                IQueryable<DbContacto> query = ctxCrm.DbContactoes.Where(c => c.EmpresaId == searchParam.EmpresaId);

                string searchTerm = ListsCrm.PrepareForSearch(nameOrdocOrEmail);

                string[] termSplit = searchTerm.Split(' ');                

                decimal nroDoc;
                if (decimal.TryParse(searchTerm, out nroDoc))
                {
                    query = query.Where(c => c.NroDocumento.HasValue && c.NroDocumento.Value == nroDoc);
                }
                else
                {
                    if (termSplit.Length > 1)
                    {
                        foreach (var term in termSplit)
                        {
                            string trimTerm = term.Trim();                            
                            query = query.Where(c => c.NombreSearch.Contains(trimTerm) || c.ApellidoSearch.Contains(trimTerm));
                        }
                    }
                    else
                    {
                        query = query.Where(c => c.Email.Contains(nameOrdocOrEmail) || c.NombreSearch.Contains(searchTerm) || c.ApellidoSearch.Contains(searchTerm));
                    }
                }       

                //query = query.Where(exp);

                int totalDeResultados = query.Count();

                query = query.OrderBy(c => c.Nombre);

                result.TotalDeResultados = totalDeResultados;

                if (searchParam.PageSize != 0)
                {
                    query = query.Skip(searchParam.PageSkip).Take(searchParam.PageSize);
                }

                List<DbContacto> dbContactoList = query.ToList();

                result.PageIndex = searchParam.PageSkip;
                result.PageSize = searchParam.PageSize;               
                
                foreach (DbContacto dbContacto in dbContactoList)
                {
                    registro = new PtoVentaRegistroCliente();
                    registro.Id = dbContacto.Id;
                    registro.TipoDocumentoId = dbContacto.TipoDocumentoId;
                    registro.Dni = dbContacto.NroDocumento;
                    registro.Email = dbContacto.Email;
                    registro.Nombre = dbContacto.Nombre;
                    registro.Apellido = dbContacto.Apellido;
                    registro.NacionalidadId = dbContacto.NacionalidadId;
                    registro.ProvinciaId = dbContacto.ProvinciaId;
                    registro.Domicilio = dbContacto.Domicilio;
                    registro.CodigoPostal = dbContacto.CodigoPostal;
                    registro.CumpleDia = dbContacto.CumpleDia;
                    registro.CumpleMes = dbContacto.CumpleMes;
                    registro.CumpleAnio = dbContacto.CumpleAnio;
                    registro.EstadoEmail = dbContacto.EstadoEmail;
                    registro.EmpresaId = dbContacto.EmpresaId;
                    registro.NroCredencial = dbContacto.NroCredencial;
                    registro.Telefono = dbContacto.Telefono;
                    registro.DeseaRecibirEmails = dbContacto.DeseaRecibirEmails;
                    registro.Estado = dbContacto.Estado;
                    registro.CantidadHijos = dbContacto.CantidadHijos;
                    registro.EdadHijoMenor = dbContacto.EdadHijoMenor;

                    if (dbContacto.Sexo.HasValue)
                    {
                        registro.Sexo = dbContacto.Sexo.Value ? 1 : 0;
                    }

                    if (dbContacto.ContactoVenta != null)
                    {
                        registro.FechaUltimaCompra = dbContacto.ContactoVenta.FechaUltimaCompra;
                    }

                    registro.Categorias.AddRange(dbContacto.Categorias.Select(c => new MaestroBase() { Id = c.Id, Nombre = c.Nombre }).ToList());
                    registroList.Add(registro);
                }
            }
                        
            result.Resultados.AddRange(registroList);

            return result;
        }

        public PtoVentaRegistroCliente SaveCustomer(PtoVentaRegistroCliente customer)
        {
            bool sendEmail = false;
            DateTime dateTimeNow = DateTime.Now;
            bool esNuevo = false;
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CrmContactoEntities ctxCrm = new CrmContactoEntities())
                {
                    List<DbContactoBitacora> contactoBitacoraList = new List<DbContactoBitacora>();

                    DbContacto dbContacto;
                    if (customer.Id != default(int))
                    {
                        dbContacto = ctxCrm.DbContactoes.Where(c => c.Id == customer.Id).Single();
                        esNuevo = false;
                    }
                    else
                    {
                        esNuevo = true;                        

                        dbContacto = new DbContacto();
                        ctxCrm.DbContactoes.AddObject(dbContacto);
                        dbContacto.AuditFechaCreacion = dateTimeNow;
                        dbContacto.AuditUserNameCreacion = customer.UserName;
                        dbContacto.EstadoEmail = (int)EstadoEmail.Alta;
                        dbContacto.OrigenPuntoDeVentaId = customer.PuntoDeVentaId;
                        dbContacto.OrigenId = (int)TipoContactoOrigen.PuntoDeVenta;
                        dbContacto.Estado = (int)EstadoCliente.Activo;

                        AgregarBitacoraCreacion(contactoBitacoraList, customer, dateTimeNow);

                        sendEmail = customer.DeseaRecibirEmails;
                    }

                    if (String.IsNullOrEmpty(customer.Email) && !customer.Dni.HasValue)
                        throw new SvcBusinessException(LocalizationProvider.Instance["ExceptionClienteSinEmail"]);

                    // valido que no exista
                    if (ctxCrm.DbContactoes.FilterLogicalRemoved().Where(c => c.Email == customer.Email && c.Id != customer.Id && c.EmpresaId == customer.EmpresaId).Count() > 0)
                        throw new SvcBusinessException(LocalizationProvider.Instance["ExceptionYaExisteClienteConEseEmail"]);

                    // valido el número de documento
                    if (customer.Dni.HasValue)
                    {
                        IQueryable<DbContacto> queryContacto = ctxCrm.DbContactoes.FilterLogicalRemoved();
                        queryContacto = queryContacto.Where(c => c.NroDocumento == customer.Dni && c.Id != customer.Id && c.EmpresaId == customer.EmpresaId);                       

                        if (queryContacto.Count() > 0)
                            throw new SvcBusinessException(LocalizationProvider.Instance["ExceptionYaExisteClienteConEseDNI"]);
                    }

                    if (customer.CumpleAnio.HasValue)
                    {
                        Dictionary<string, string> config = ListsCrm.GetCompanyConfigurationKeyValues(customer.EmpresaId);
                        if (config.ContainsKey(CommonConstants.ValidacionMaximoEdad))
                        {
                            int maximoEdad = Convert.ToInt32(config[CommonConstants.ValidacionMaximoEdad]);
                            if ((DateTime.Now.Date.Year - customer.CumpleAnio.Value) < maximoEdad)
                            {
                                throw new SvcBusinessException(string.Format(LocalizationProvider.Instance["Validacion.EdadMaxima"], maximoEdad));
                            }
                        }
                    }              

                    dbContacto.AuditFechaModificacion = dateTimeNow;
                    dbContacto.AuditUserNameModificacion = customer.UserName;

                    if (dbContacto.Id != default(int))
                    {
                        AgregarBitacoraModificacion(contactoBitacoraList, customer, dbContacto, dateTimeNow);
                    }

                    // verifico el cambio de email
                    if (!String.IsNullOrEmpty(customer.Email))
                    {
                        if (dbContacto.Email != customer.Email)
                        {
                            dbContacto.EstadoEmail = (int)EstadoEmail.Alta;
                            AgregarBitacoraModificacionEmail(contactoBitacoraList, customer, dbContacto, dateTimeNow);
                        }

                        dbContacto.Email = customer.Email.ToLower();
                    }

                    dbContacto.Id = customer.Id;
                    dbContacto.TipoDocumentoId = customer.TipoDocumentoId;
                    dbContacto.NroDocumento = customer.Dni;


                    if (!String.IsNullOrEmpty(customer.Nombre))
                    {
                        dbContacto.Nombre = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(customer.Nombre.ToLower());
                    }

                    if (!String.IsNullOrEmpty(customer.Apellido))
                    {
                        dbContacto.Apellido = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(customer.Apellido.ToLower());
                    }

                    dbContacto.NombreSearch = ListsCrm.PrepareForSearch(customer.Nombre);
                    dbContacto.ApellidoSearch = ListsCrm.PrepareForSearch(customer.Apellido);
                    dbContacto.NacionalidadId = customer.NacionalidadId;
                    dbContacto.ProvinciaId = customer.ProvinciaId;
                    dbContacto.Domicilio = customer.Domicilio;
                    dbContacto.CodigoPostal = customer.CodigoPostal;
                    dbContacto.CumpleDia = customer.CumpleDia;
                    dbContacto.CumpleMes = customer.CumpleMes;
                    dbContacto.CumpleAnio = customer.CumpleAnio;
                    dbContacto.EmpresaId = customer.EmpresaId;
                    dbContacto.Telefono = customer.Telefono;
                    dbContacto.NroCredencial = customer.NroCredencial;
                    dbContacto.DeseaRecibirEmails = customer.DeseaRecibirEmails;
                    dbContacto.CantidadHijos = customer.CantidadHijos;
                    dbContacto.EdadHijoMenor = customer.EdadHijoMenor;

                    if (customer.Sexo.HasValue)
                    {
                        dbContacto.Sexo = customer.Sexo.Value == (int)SexoEnum.Masculino;
                    }

                    foreach (var factura in customer.Facturas)
                    {
                        if (dbContacto.ContactoVentas.Where(v => v.NroFactura == factura.Factura && v.PuntoDeVentaId == factura.PuntoDeVentaId).Count() == 0)
                        {
                            if (!factura.FechaDeVenta.HasValue)
                            {
                                factura.FechaDeVenta = DateTime.Now;
                            }

                            DbContactoVentaPorPdv dbContactoVenta = new DbContactoVentaPorPdv();
                            dbContactoVenta.FechaVenta = factura.FechaDeVenta.Value;
                            dbContactoVenta.NroFactura = factura.Factura;
                            dbContactoVenta.AccionDeMarketingId = factura.AccionDeMarketingId;
                            dbContactoVenta.PuntoDeVentaId = factura.PuntoDeVentaId;
                            dbContactoVenta.AuditFechaCreacion = dateTimeNow;
                            dbContactoVenta.AuditUserNameCreacion = customer.UserName;
                            dbContactoVenta.VentaValida = true;
                            dbContacto.ContactoVentas.Add(dbContactoVenta);

                            AgregarBitacoraNuevaVenta(contactoBitacoraList, factura, customer.UserName);
                        }
                        else
                        {
                            customer.ServiceMessage += string.Format(LocalizationProvider.Instance["MensajeFacturaYaExisteEnSistema"], factura.Factura);
                        }
                    }

                    foreach (DbContactoBitacora bitacora in contactoBitacoraList)
                    {
                        dbContacto.ContactoBitacoras.Add(bitacora);
                    }

                    ctxCrm.SaveChanges();
                    customer.Id = dbContacto.Id;

                    var promocionesListForValidar = MarketingPromocionesManager.Instance.GetPromocionesVigentes(customer.EmpresaId);
                    foreach (var promocion in promocionesListForValidar)
                    {
                        promocion.ValidarAlAsociarPromocion(customer, esNuevo);
                    }

                    tScope.Complete();                    
                }
            }

            var promocionesList = MarketingPromocionesManager.Instance.GetPromocionesVigentes(customer.EmpresaId);

            PromocionResultado promocionResultado = new PromocionResultado();
            foreach (var promocion in promocionesList)
            {
                promocionResultado = promocion.CrearPromocion(customer, esNuevo);
                if (!promocionResultado.ContinuarProcesando)
                {
                    break;
                }
            }

            if (sendEmail && promocionResultado.EnviarEmailDeBienvenida)
            {
                ContactoForEmail contactoForEmail = new ContactoForEmail();
                contactoForEmail.ContactoId = customer.Id;
                contactoForEmail.Email = customer.Email;
                contactoForEmail.EmpresaId = customer.EmpresaId;
                contactoForEmail.UserName = customer.UserName;
                contactoForEmail.Origen = (int)TipoContactoOrigen.PuntoDeVenta;
                CommonCrmTaskManager.SendEmailToCustomerInThread(contactoForEmail);
            }

            return customer;
        }
      
        private void AgregarBitacoraNuevaVenta(List<DbContactoBitacora> bitacoraList, FacturaCampanaPtoVta factura, string userName)
        {
            DbContactoBitacora dbContactoBitacora = new DbContactoBitacora();

            dbContactoBitacora.TipoDeRegistro = (int)TipoRegistroBitacora.Venta;
            if (factura.AccionDeMarketingId.HasValue)
            {
                dbContactoBitacora.Accion = string.Format(LocalizationProvider.Instance["BitacoraMsgRelacionVentaCamapana"], factura.Factura, factura.AccionDeMarketingId);
            }
            else
            {
                dbContactoBitacora.Accion = string.Format(LocalizationProvider.Instance["BitacoraMsgRelacionVenta"], factura.Factura);
            }

            dbContactoBitacora.AuditUserNameCreacion = userName;
            dbContactoBitacora.AuditFechaCreacion = DateTime.Now;

            bitacoraList.Add(dbContactoBitacora);
        }

        private static void AgregarBitacoraEmail(List<DbContactoBitacora> bitacoraList, string mensaje, string userName, DateTime now)
        {
            DbContactoBitacora dbContactoBitacora = new DbContactoBitacora();
            dbContactoBitacora.TipoDeRegistro = (int)TipoRegistroBitacora.Email;
            dbContactoBitacora.Accion = mensaje;
            dbContactoBitacora.AuditUserNameCreacion = userName;
            dbContactoBitacora.AuditFechaCreacion = now;
            bitacoraList.Add(dbContactoBitacora);
        }

        private static void AgregarBitacoraModificacion(List<DbContactoBitacora> bitacoraList, PtoVentaRegistroCliente customer, DbContacto dbContacto, DateTime now)
        {
            //DbContactoBitacora dbContactoBitacora = new DbContactoBitacora();

            //dbContactoBitacora.TipoDeRegistro = (int)TipoRegistroBitacora.Modificacion;
            //dbContactoBitacora.AuditUserNameCreacion = customer.UserName;
            //dbContactoBitacora.AuditFechaCreacion = DateTime.Now;

            //StringBuilder builder = new StringBuilder();
            //bool cambio = false;
            //if (dbContacto.NroDocumento != customer.Dni)
            //{
            //    builder.AppendFormat("NroDocumento de {0} a {1}", dbContacto.NroDocumento, customer.Dni);
            //    builder.AppendLine();
            //    cambio = true;
            //}

            //if (dbContacto.Email != customer.Email)
            //{
            //    builder.AppendFormat("Email de {0} a {1}", dbContacto.Email, customer.Email);
            //    builder.AppendLine();
            //    cambio = true;
            //}

            //if (dbContacto.Nombre != customer.Nombre)
            //{
            //    builder.AppendFormat("Nombre de {0} a {1}", dbContacto.Nombre, customer.Nombre);
            //    builder.AppendLine();
            //    cambio = true;
            //}

            //if (dbContacto.Apellido != customer.Apellido)
            //{
            //    builder.AppendFormat("Apellido de {0} a {1}", dbContacto.Apellido, customer.Apellido);
            //    builder.AppendLine();
            //    cambio = true;
            //}

            ////if (!string.IsNullOrEmpty(customer.FechaCumpleanos))
            ////{
            ////    DateTime fechaCumple;
            ////    if (DateTime.TryParseExact(customer.FechaCumpleanos, "dd/MM/yyyy", null, System.Globalization.DateTimeStyles.None, out fechaCumple))
            ////    {
            ////        if (dbContacto.FechaCumpleanos != fechaCumple.Date)
            ////        {
            ////            builder.AppendFormat("FechaCumpleanos de {0} a {1}", dbContacto.FechaCumpleanos, customer.FechaCumpleanos);
            ////            builder.AppendLine();
            ////            cambio = true;
            ////        }
            ////    }
            ////}

            //dbContactoBitacora.Accion = builder.ToString();

            //if (cambio)
            //{
            //    bitacoraList.Add(dbContactoBitacora);
            //}
        }

        private static void AgregarBitacoraModificacionEmail(List<DbContactoBitacora> bitacoraList, PtoVentaRegistroCliente customer, DbContacto dbContacto, DateTime now)
        {
            DbContactoBitacora dbContactoBitacora = new DbContactoBitacora();

            dbContactoBitacora.TipoDeRegistro = (int)TipoRegistroBitacora.Modificacion;
            dbContactoBitacora.AuditUserNameCreacion = customer.UserName;
            dbContactoBitacora.AuditFechaCreacion = now;

            StringBuilder builder = new StringBuilder();
            bool cambio = false;

            if (!String.IsNullOrEmpty(dbContacto.Email) && !String.IsNullOrEmpty(customer.Email) && dbContacto.Email != customer.Email)
            {
                builder.AppendFormat(LocalizationProvider.Instance["BitacoraMsgModificacionEmail"], dbContacto.Email, customer.Email);
                builder.AppendLine();
                cambio = true;
            }

            dbContactoBitacora.Accion = builder.ToString();

            if (cambio)
            {
                bitacoraList.Add(dbContactoBitacora);
            }
        }

        private static void AgregarBitacoraCreacion(List<DbContactoBitacora> bitacoraList, PtoVentaRegistroCliente customer, DateTime now)
        {
            DbContactoBitacora dbContactoBitacora = new DbContactoBitacora();

            dbContactoBitacora.TipoDeRegistro = (int)TipoRegistroBitacora.Creacion;
            dbContactoBitacora.Accion = string.Format(LocalizationProvider.Instance["BitacoraMsgCreacionContacto"], customer.UserName, now);
            dbContactoBitacora.AuditUserNameCreacion = customer.UserName;
            dbContactoBitacora.AuditFechaCreacion = now;

            bitacoraList.Add(dbContactoBitacora);

        }

        public PuntoDeVenta GetPtoVentaCodeById(int puntoDeVentaId)
        {
            PuntoDeVenta ptoVta = new PuntoDeVenta();
            using (CrmContactoEntities ctxCrm = new CrmContactoEntities())
            {
                var dbPtoVta = ctxCrm.DbPuntoDeVentas.Where(p => p.Id == puntoDeVentaId).SingleOrDefault();
                if (dbPtoVta != null)
                {
                    ptoVta = new PuntoDeVenta();
                    ptoVta.Id = puntoDeVentaId;
                    ptoVta.CodigoExterno = dbPtoVta.CodigoExterno;
                    // TODO
                }
            }

            return ptoVta;
        }

        public Cliente GetCustomerById(ServiceOptions options, int customerId, ClienteByIdOptions clientOptions)
        {
            CrmContactoAdminService svc = new CrmContactoAdminService();
            return svc.GetCustomerById(options, customerId, clientOptions);
        }

        public PdvCantidadTotalesVentaResult GetCantidadTotalesVenta(PdvCantidadTotalesVentaSearch search)
        {
            PdvCantidadTotalesVentaResult result = new PdvCantidadTotalesVentaResult();
            using (CrmContactoEntities ctxCrm = new CrmContactoEntities())
            {
                long total = 0;
                long totalVentas = 0;
                long totalSucursal = 0;
                ObjectParameter oparam = new ObjectParameter("total", total);
                totalVentas = ctxCrm.GetCantidadVentasPorSucursal(search.CompanyId, search.CodigoSucursal, search.Desde, search.Hasta, oparam).Single().Value;

                totalSucursal = ctxCrm.GetCantidadVentasPorSucursalEnCRM(search.CompanyId, search.CodigoSucursal, search.Desde, search.Hasta, oparam).Single().Value;

                result.CantidadVentasSucursal = totalSucursal;
                result.CantidadVentasTotal = totalVentas;
            }

            return result;
        }

        public List<TipoMensajeBitacora> GetTipoMensajeBitacora(TipoMensajeBitacoraSearch search)
        {
            CrmContactoAdminService svc = new CrmContactoAdminService();
            return svc.GetTipoMensajeBitacora(search);
        }

        public ClienteBitacora SaveCustomerBitacora(ServiceOptions options, ClienteBitacora clienteBitacora)
        {
            CrmContactoAdminService svc = new CrmContactoAdminService();
            return svc.SaveCustomerBitacora(options, clienteBitacora);
        }

        public List<PuntoDeVenta> GetPuntoDeVentaDto(ServiceOptions options, PuntoDeVentaSearch search)
        {
            CrmContactoAdminService svc = new CrmContactoAdminService();
            return svc.GetPuntoDeVentaDto(options, search);
        }
    }
}
